/******************************************************************************
Project    : Real time rtsp server program
*******************************************************************************
File Name    :  <RtspServer.cpp>:  real time rtsp server interface source file
Module Name  :  
Description  :  None
History      :
 No.   Ver.     Date        Designed by  Comment
-----+--------+----------+------------+---------------------------------------
 001   0.00.01  10/20/2015  <3G@LIURENHUA>   <real time rtsp server interface source file>
*******************************************************************************/
#include "RtspServerInterface.h"

//#define DEBUG_RTSP
#ifdef DEBUG_RTSP
#include <utils/Log.h>
#endif /* DEBUG_RTSP */
/******************************************************************************
  macro define
 ******************************************************************************/
#define SMSS_CLASS1 AudioRTimeServerMediaSubsession
#define SMSS_CLASS2 VideoRTimeServerMediaSubsession
#define SMSS_CLASS3 Mp2TsRTimeServerMediaSubsession

/******************************************************************************
  thread functions define (static)
 ******************************************************************************/
static void* pvStartTaskScheduler(void *pvThreadArg)
{
	RealTimeRtspServer *pctSvr = NULL;
	if( (NULL != pvThreadArg) ){
		pctSvr = (RealTimeRtspServer*)pvThreadArg;
		pctSvr->eStartTaskScheduler();
	}
	return NULL;
}

/******************************************************************************
  class functions define
 ******************************************************************************/
void RtspServerInterface::vQueueInit(
	queue_t** pstQue, QueType eType, int msize, int delay)
{
	q_init(pstQue, eType, msize, delay);
}

#ifdef DEBUG_PACKETNO
void RtspServerInterface::vQuePushData(int number, 
	const char *encType, const uint8_t *mBuffer, size_t mSize, 
	queue_t* pstQue)
#else
void RtspServerInterface::vQuePushData(const char *encType, 
	const uint8_t *mBuffer, size_t mSize, queue_t* pstQue)
#endif /* DEBUG_PACKETNO */
{
	int bufferSize = 0;
	uint8_t* pucTmp = NULL;
	AVPacket *packet = NULL;
	
	if( (mSize <= 5)  || (NULL == pstQue) ){return;}
	if( !strncmp(encType, "AVC", strlen("AVC")) ){
#ifdef DEBUG_RTSP
		//__android_log_print(ANDROID_LOG_DEBUG, 
		//	"RtspServerInterface", "vQuePushData[%s] [%d]\n", encType, mSize);
#endif /* DEBUG_RTSP */
		if(mBuffer[0] == 0x00 && mBuffer[1]==0x00 && mBuffer[2]==0x00
		    && mBuffer[3]==0x01 && mBuffer[4]==0x67){ /* SPS,PPS*/
			if(pstQue->pps != NULL){
				free(pstQue->pps);
				pstQue->pps = NULL;
			}
			pstQue->pps = (char *)malloc(sizeof(char)*(mSize));
			memcpy(pstQue->pps,mBuffer,mSize);
			pstQue->ppsL = mSize;
			pstQue->ppsB = true;
			return;
		}
		if(mBuffer[0] == 0x00 && mBuffer[1]==0x00 && mBuffer[2]==0x00
		    && mBuffer[3]==0x01 && mBuffer[4]==0x65){
			if(pstQue->ppsB != true){
				bufferSize = pstQue->ppsL;
			}
			pstQue->ppsB = false;
		}
	}else if( !strncmp(encType, "HEVC", strlen("HEVC")) ){
#ifdef DEBUG_RTSP
		//__android_log_print(ANDROID_LOG_DEBUG, 
		//	"RtspServerInterface", "vQuePushData[%s] [%d]\n", encType, mSize);
#endif /* DEBUG_RTSP */
		if(mBuffer[0] == 0x00 && mBuffer[1]==0x00 && mBuffer[2]==0x00
		    && mBuffer[3]==0x01 && mBuffer[4]==0x40){ /* VPS,SPS,PPS*/
			if(pstQue->pps != NULL){
				free(pstQue->pps);
				pstQue->pps = NULL;
			}
			pstQue->pps = (char *)malloc(sizeof(char)*(mSize));
			memcpy(pstQue->pps,mBuffer,mSize);
			pstQue->ppsL = mSize;
			pstQue->ppsB = true;
			return;
		}
		if(mBuffer[0] == 0x00 && mBuffer[1]==0x00 && mBuffer[2]==0x00
		    && mBuffer[3]==0x01 && mBuffer[4]==0x26){
		    if(pstQue->ppsB != true){
				bufferSize = pstQue->ppsL;
		    }
		    pstQue->ppsB = false;
		}	
	}
#ifdef AUDIO_ENABLE
	else if( !strncmp(encType, "AAC", strlen("AAC")) ){
	}
#endif /* AUDIO_ENABLE */
	/* Set pointer to start address */
	packet = (AVPacket*)malloc(sizeof(AVPacket));
	if ( (NULL == packet) ) {
#ifdef DEBUG_RTSP
		__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "malloc packet failed\n");
#endif /* DEBUG_RTSP */
		return;
	}
	
	/* Allocate a new frame object. */
	packet->data = pucTmp =
		(uint8_t*)malloc( (mSize + bufferSize) );
	if( (NULL == packet->data) ){
#ifdef DEBUG_RTSP
		__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "malloc data failed\n");
#endif /* DEBUG_RTSP */
		free(packet);
		return;
	}
#ifdef DEBUG_PACKETNO
	packet->number = number;
#endif /* DEBUG_PACKETNO */

	if( (0  !=  bufferSize) ){
		memcpy(pucTmp, pstQue->pps, pstQue->ppsL);
		pucTmp += pstQue->ppsL;
	}
	memcpy(pucTmp, mBuffer, mSize);
	packet->size = mSize + bufferSize;
	q_push_head(pstQue, packet);
}

void RtspServerInterface::vQueueDInit(queue_t** pstQue)
{
	if( ((*pstQue) != NULL) ){
		q_free(pstQue, free_AVPacket);
		*pstQue = NULL;
	}
}
/******************************************************************************
  class functions define
 ******************************************************************************/
RtspServerInterface::RtspServerInterface(u_int16_t usPort) : pctUsgEnv(NULL), pctSvr(NULL)
{
	/* Create rtsp server */
	pctSvr =  new RealTimeRtspServer(usPort);
#ifdef DEBUG_RTSP
	if( (NULL == pctSvr) ){
		__android_log_print(ANDROID_LOG_DEBUG, 
				"RtspServerInterface", "pstSvr is null\n");
	}
#endif /* DEBUG_RTSP */
	
	/* Clear thread identity */
	threadId = 0;
	/* Clear start flag */
	start = false;
#ifdef DEBUG_RTSP
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "RtspServerInterface end\n");
#endif /* DEBUG_RTSP */
}

void RtspServerInterface::vCreateSMS(){
	if( (NULL != pctSvr) ){
		RTSPSVR_ERR_et eRet = RTSPSVR_ERR_NOERR;
		/* Create SMS */
		eRet = pctSvr->eCreateSMS(
			"live", NULL, "www rtsp live", false, NULL);
#ifdef DEBUG_RTSP
		if( (RTSPSVR_ERR_NOERR != eRet) ){
			__android_log_print(ANDROID_LOG_DEBUG, 
					"RtspServerInterface", "eCreateSMS failed\n");
		}
#endif /* DEBUG_RTSP */

		/* Get usage environment */
		pctUsgEnv =  pctSvr->pctGetUsageEnv();
#ifdef DEBUG_RTSP
		if( (NULL == pctUsgEnv) ){
			__android_log_print(ANDROID_LOG_DEBUG, 
					"RtspServerInterface", 
					"pctUsgEnv is null\n");
		}
#endif /* DEBUG_RTSP */
	}
#ifdef DEBUG_RTSP
	else{
			__android_log_print(ANDROID_LOG_DEBUG, 
					"RtspServerInterface", "vCreateSMS failed\n");
	}
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "vCreateSMS end\n");
#endif /* DEBUG_RTSP */
}

void RtspServerInterface::vAddAudioSMSSToSMS(tEsFmt eCodecId, CH_CFG_et eChCfg, 
	FS_IDX_et eFsIdx, PROFILE_et eProfile, Boolean bWideBand, u_int8_t ucChNum, 
	queue_t* pstQue)
{
	if( (NULL != pctSvr)  && (NULL != pctUsgEnv) ){
		RTSPSVR_ERR_et eRet = RTSPSVR_ERR_NOERR;
		eRet = pctSvr->eAddSMSSToSMS(
			SMSS_CLASS1::createNew(
				*pctUsgEnv,
				eCodecId, 
				eChCfg, 
				eFsIdx, 
				eProfile,
				bWideBand,
				ucChNum,
				pstQue) );
#ifdef DEBUG_RTSP
		if( (RTSPSVR_ERR_NOERR != eRet) ){
			__android_log_print(ANDROID_LOG_DEBUG, 
					"RtspServerInterface", "eAddSMSSToSMS failed\n");
		}
#endif /* DEBUG_RTSP */	
	}
#ifdef DEBUG_RTSP
	else{
			__android_log_print(ANDROID_LOG_DEBUG, 
					"RtspServerInterface", "vAddAudioSMSSToSMS failed\n");
	}
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "vAddAudioSMSSToSMS end\n");
#endif /* DEBUG_RTSP */
}

void RtspServerInterface::vAddVideoSMSSToSMS(
	tEsFmt eCodecId, u_int8_t ucFrmRate, queue_t* pstQue)
{
	if( (NULL != pctSvr)  && (NULL != pctUsgEnv) ){
		RTSPSVR_ERR_et eRet = RTSPSVR_ERR_NOERR;
		eRet = pctSvr->eAddSMSSToSMS(
			SMSS_CLASS2::createNew(
			*pctUsgEnv, 
			eCodecId, 
			ucFrmRate,
			pstQue) );
#ifdef DEBUG_RTSP
		if( (RTSPSVR_ERR_NOERR != eRet) ){
			__android_log_print(ANDROID_LOG_DEBUG, 
					"RtspServerInterface", "eAddSMSSToSMS failed\n");
		}
#endif /* DEBUG_RTSP */	
	}
#ifdef DEBUG_RTSP
	else{
			__android_log_print(ANDROID_LOG_DEBUG, 
					"RtspServerInterface", "vAddVideoSMSSToSMS failed\n");
	}
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "vAddVideoSMSSToSMS end\n");
#endif /* DEBUG_RTSP */
}

void RtspServerInterface::vAddTsSMSSToSMS(queue_t* pstQue)
{
	if( (NULL != pctSvr)  && (NULL != pctUsgEnv) ){
		RTSPSVR_ERR_et eRet = RTSPSVR_ERR_NOERR;
		eRet = pctSvr->eAddSMSSToSMS(
			SMSS_CLASS3::createNew(
				*pctUsgEnv,  
				pstQue) );
#ifdef DEBUG_RTSP
		if( (RTSPSVR_ERR_NOERR != eRet) ){
			__android_log_print(ANDROID_LOG_DEBUG, 
					"RtspServerInterface", "eAddSMSSToSMS failed\n");
		}
#endif /* DEBUG_RTSP */	
	}
#ifdef DEBUG_RTSP
	else{
			__android_log_print(ANDROID_LOG_DEBUG, 
					"RtspServerInterface", "vAddTsSMSSToSMS failed\n");
	}
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "vAddTsSMSSToSMS end\n");
#endif /* DEBUG_RTSP */
}

void RtspServerInterface::vStartTaskScheduler()
{
	if( (NULL != pctSvr) ){
		RTSPSVR_ERR_et eRet = RTSPSVR_ERR_NOERR;
		/* Add SMS to rtsp server */
		eRet = pctSvr->eAddSMSToRtspSvr();
#ifdef DEBUG_RTSP
		if( (RTSPSVR_ERR_NOERR != eRet) ){
			__android_log_print(ANDROID_LOG_DEBUG, 
					"RtspServerInterface", "eAddSMSToRtspSvr failed\n");
		}
#endif /* DEBUG_RTSP */
		/* Create thread start task scheduler */
		pthread_create(&threadId, NULL,
			pvStartTaskScheduler, (void*)pctSvr);
		/* Setting start flag */
		start = true;
	}
#ifdef DEBUG_RTSP
	else{
			__android_log_print(ANDROID_LOG_DEBUG, 
					"RtspServerInterface", "vStartTaskScheduler failed\n");
	}
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "vStartTaskScheduler end\n");
#endif /* DEBUG_RTSP */
}

void RtspServerInterface::vStopTaskScheduler()
{
	if( (NULL != pctSvr) ){
		pctSvr->vStopTaskScheduler();
		if( (threadId > 0) ){
			pthread_join(threadId, NULL);
			threadId = 0;
		}
		start = false;
	}
#ifdef DEBUG_RTSP
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "vStopTaskScheduler end\n");
#endif /* DEBUG_RTSP */
}

void RtspServerInterface::vResetRtspServer()
{
	if( (NULL != pctSvr) ){
		pctSvr->vResetRtspServer();
	}
#ifdef DEBUG_RTSP
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "vResetRtspServer end\n");
#endif /* DEBUG_RTSP */
}

RtspServerInterface::~RtspServerInterface()
{
	if( (NULL != pctSvr) ){
		pctSvr->vResetRtspServer();
		pctSvr->vStopTaskScheduler();
		if( (threadId > 0) ){
			pthread_join(threadId, NULL);
			threadId = 0;
		}
		delete pctSvr;
		pctSvr = NULL;
	}
#ifdef DEBUG_RTSP
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "RtspServerInterface end\n");
#endif /* DEBUG_RTSP */
}
